﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Indexing;
using Common;
using System.Threading;
using Notifying;
using System.Net;
using Site_Extractor;

namespace Server
{
    public class Server
    {
        public const int NUM_OF_THREADS_PER_SITE = 4;
        string _connectionString, _prefixFilePath;
        List<Site> _sites;
		List<GenericForum> _forums;
        Thread[] _aThreads;
        Indexer _indexer;
        Catalog[] _catalogs;
        Catalog _mainCatalog;
        IAsyncResult[] _asyncResults;
        public Notifier _notifier; //Allows to plug in a notifier as needed.
        static object Object = new object();

        public Server(List<Site> Sites,List<GenericForum> forums,  string ConnectionString, string PrefixFilePath)
        {
			_forums = forums;
            _connectionString = ConnectionString;
            _sites = Sites;
            _indexer = new Indexer(new Catalog(_prefixFilePath), ConnectionString, PrefixFilePath, 6);
            _prefixFilePath = PrefixFilePath;
            _aThreads = new Thread[_sites.Count];
            _catalogs = new Catalog[_sites.Count];
            _asyncResults = new IAsyncResult[_sites.Count];
            _mainCatalog = new Catalog(_prefixFilePath);

            _notifier = new Notifier(60, _mainCatalog, ConnectionString, _prefixFilePath);
            _notifier.StartNotificationTimer();


        }


        public void CreateDnsLookupHash()
        {
            HtmlDownloader.DnsLookup = new System.Collections.Hashtable();
            foreach (Site site in _sites)
            {
                foreach (string domain in site.Domains)
                {
                    if (domain.Equals(string.Empty)) continue;
                    IPAddress[] addresslist = Dns.GetHostAddresses(domain);
                    foreach (IPAddress ip in addresslist)
                    {
                        if (!HtmlDownloader.DnsLookup.Contains(domain))
                            HtmlDownloader.DnsLookup.Add(domain, ip.ToString());
                    }
                }
            }

        }

        /// <summary>
        /// This is the main index cycle function.
        /// </summary>
        /// <param name="FromDate"></param>
        public void DoUpdateCycle(DateTime FromDate)
        {
            //Reset index.
            //_indexer = new Indexer(_connectionString, _prefixFilePath);
            _mainCatalog = new Catalog(_prefixFilePath);
            _notifier.SetCatalogReference(_mainCatalog);
            //JobManager.SetMaxThreads(22, 22);
            
            for (int i = 0; i < _sites.Count; ++i)
            {
                _aThreads[i] = new Thread(new ParameterizedThreadStart(IndexSiteThread));
                _aThreads[i].Start(new object[] { _sites[i], FromDate });
   
            }
            for (int i = 0; i < _sites.Count; ++i)
            {
                _aThreads[i].Join();
            }
            /*
			for (int i=0 ; i< _forums.Count; i++)
			{
				JobManager.AddJob(IndexForumThread, new object[] { _forums[i], FromDate});
			}
            */
            Thread.Sleep(2000);
            JobManager.WaitForAll();

            //ReTry timedout jobs.
            /*
            for (
                int i = 12; i < 13; ++i)
            {
                JobManager.AddJob(RetryTimedoutJobs, new object[] { _sites[i], FromDate });
            }
			JobManager.WaitForAll();
            */

            //Indexing Done.
            Console.Write("Indexing ended at : " + DateTime.Now.ToString());
            //All sites were crawled, now run all queries and notify.
            _notifier.NotifyUsersRealTime();

        }

		private void IndexForumThread(object o)
		{
			try
			{
				object[] objs = o as object[];
				GenericForum f = objs[0] as GenericForum;
				DateTime from = (DateTime)objs[1];
				_indexer.IndexForum(f, from);
			}
			catch (Exception ex){
				Console.WriteLine(ex.Message);
			}
		}

        private void RetryTimedoutJobs(object obj)
        {
            string linkToIndex = string.Empty;
            if (obj == null) return;
            if (!(obj is object[])) return;
            var objs = obj as object[];
            if (objs.Length != 2) return;
            foreach (object o in objs) if (o == null) return;
            var site = objs[0] as Site;
            var date = (DateTime)objs[1];
            RetryTimedoutJobs(site, date);

        }

        private void IndexSiteThread(object obj)
        {
            string linkToIndex = string.Empty;
            if (obj == null) return;
            if (!(obj is object[])) return;
            var objs = obj as object[];
            if (objs.Length != 2) return;
            foreach (object o in objs) if (o == null) return;
            var site = objs[0] as Site;
            var date = (DateTime)objs[1];
            IndexStories(site, date);
            IndexBlogs(site, date);
            IndexForums(site, date);
        }


        private void RetryTimedoutJobs(Site Site, DateTime FromDate)
        {
            try
            {
                _indexer.RetryTimedOutJobs(Site, FromDate);
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception: {0}", e.Message);
            }
        }

        //private delegate void IndexSiteDelegate( Site Site, DateTime FromDate);
        /// <summary>
        /// Indexes an entire site and merges the newly indexed catalog into the main one.
        /// </summary>
        /// <param name="Site"></param>
        /// <returns></returns>
        private void IndexStories(Site Site, DateTime FromDate)
        {

            try
            {
                Indexer indexer = new Indexer(_mainCatalog, _connectionString, _prefixFilePath, NUM_OF_THREADS_PER_SITE);
                indexer.IndexStories(Site, "", FromDate);
            }
            catch (Exception e) 
            {
                Console.WriteLine("Exception: {0}", e.Message);
            }
        }
        private void IndexBlogs(Site Site, DateTime FromDate)
        {
            try
            {
                Indexer indexer = new Indexer(_mainCatalog, _connectionString, _prefixFilePath, NUM_OF_THREADS_PER_SITE);

                indexer.IndexBlogs(Site, FromDate);
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception: {0}", e.Message);
            }
        }
        private void IndexForums(Site Site, DateTime FromDate)
        {
            try
            {
                Indexer indexer = new Indexer(_mainCatalog, _connectionString, _prefixFilePath, NUM_OF_THREADS_PER_SITE);

                indexer.IndexForums(Site, FromDate);
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception: {0}", e.Message);
            }
        }

    }
}
